/**
 * 
 */
package javapop.framework.parser.tuple;

import java.util.List;

import javapop.framework.ParseContext;
import javapop.framework.ParseError;
import javapop.framework.ParseInput;
import javapop.framework.ParseResult;
import javapop.framework.Parser;
import javapop.framework.parser.TupleParser;
import javapop.utils.Quadruple;

/**
 * @author Hakim Belhaouari
 *
 */
public class Four<A, B, C, D> extends Parser<Quadruple<A, B, C, D>> {

	private TupleParser parser;
	
	/**
	 * 
	 */
	public Four() {
		parser = new TupleParser();
		
	}

	public Four<A, B, C, D> then(Parser<?> silent) {
		parser.addSilent(silent);
		return this;
	}
	
	public Four<A, B, C, D> first(Parser<A> first) {
		if(parser.getArity()>=1) {
			throw new IllegalStateException("First component already set");
		}
		parser.addComponent(first);
		return this;
	}
	
	public Four<A, B, C, D> second(Parser<B> first) {
		if(parser.getArity()==0) {
			throw new IllegalStateException("First component missing");
		}
		if(parser.getArity()>1) {
			throw new IllegalStateException("Second component already set");
		}
		parser.addComponent(first);
		return this;
	}

	public Four<A, B, C, D> third(Parser<C> first) {
		if(parser.getArity()==0) {
			throw new IllegalStateException("First component missing");
		}
		if(parser.getArity()==1) {
			throw new IllegalStateException("Second component missing");
		}
		if(parser.getArity()>2) {
			throw new IllegalStateException("Third component already set");
		}
		parser.addComponent(first);
		return this;
	}
	
	public Four<A, B, C, D> fourth(Parser<D> p) {
		if(parser.getArity()==0) {
			throw new IllegalStateException("First component missing");
		}
		if(parser.getArity()==1) {
			throw new IllegalStateException("Second component missing");
		}
		if(parser.getArity()==2) {
			throw new IllegalStateException("Third component missing");
		}
		if(parser.getArity() > 3) {
			throw new IllegalStateException("Fourth component already set");
		}
		parser.addComponent(p);
		return this;
	}
	
	public Four<A, B, C, D> fatalFrom(int ref) {
		parser.setFatalFrom(ref);
		return this;
	}

	
	/**
	 * @see javapop.framework.Parser#eval(javapop.framework.ParseContext, javapop.framework.ParseInput)
	 */
	@SuppressWarnings("unchecked")
	@Override
	public ParseResult eval(ParseContext ctx, ParseInput input) {
		ParseResult<List<?>> result = parser.parse(ctx, input);
		if(result.isError()) {
			return (ParseResult) result.asError();
		}
		List<?> results = result.getResult();
		if(results.size()!=4) {
			return (ParseResult) new ParseError("Wrong cardinality: expected 4 got "+results.size());
		}
		A a = (A) results.get(0);
		B b = (B) results.get(1);
		C c = (C) results.get(2);
		D d = (D) results.get(3);
		
		Quadruple<A, B, C, D> triple = new Quadruple<A, B, C, D>(a,b,c,d);
		return buildResult(triple);
	}

	/**
	 * @see javapop.framework.Parser#getDescription()
	 */
	@Override
	public String getDescription() {
		return parser.getDescription();
	}
	
	@Override
	public boolean isMemoized() {
		return false;
	}

}
